import java.rmi.RemoteException;
import java.util.LinkedList;


public class ServerObject {
	private boolean maj = false;
	private enum StateLock {NL, RL, WL}; //etats du verrou de l'objet partagé
	private Integer id;	//id de l'objet
	private StateLock lock; //verrou
	private Object obj;	//objet
	private LinkedList<Client_itf> clients; //liste clients qui accèdent à l'objet
	
	public ServerObject (int id, Object o) {
		this.id = id;
		this.obj = o;
		this.lock = StateLock.NL;
		this.clients = new LinkedList<Client_itf>();
	}
	
	public int getId() {
		return id;
	}

	public Object lock_read(Client_itf c) {
		if (maj) {
			return null;
		}
		maj = true;
		 if (this.lock == StateLock.WL) { // Si ecrivain, la liste ne comporte qu'un seul client
			 try {						//car 1 seul client peut accéder en écriture à l'objet 
				 //Obtention de la donnee la plus a jour de l'objet partage
				 this.obj = clients.getFirst().reduce_lock(id);
			 } catch (RemoteException ex) {
				 ex.printStackTrace();
			 }
		 }
		 clients.add(c); // Ajout du client a la liste des lecteurs.
		 this.lock = StateLock.RL; // Server Obj est en etat de lecture a present.
		 maj=false;
		 return this.obj; 
	}
	
	
	public Object lock_write(Client_itf c) {
		if (maj) {
			return null;
		}
		maj = true;
		if (lock == StateLock.WL) { // Si ecrivain
			try {
				// Obtention de la donnee la plus a jour de l'objet partage
				this.obj = clients.getFirst().invalidate_writer(id);
				clients.removeFirst(); // Retrait de l'ecrivain de la liste ...
			} catch ( RemoteException ex ) {
				ex.printStackTrace();
			}
		}
		// Necessaire pour eviter une Concurrent Exception du au foreach.
		LinkedList <Client_itf> replicate = new LinkedList<Client_itf>(clients);
		for (Client_itf r : replicate) {
			if (!c.equals(r) ) { // Pour eviter d'appeler le client initiateur
				try { // de la requete.
					r.invalidate_reader(id);
				} catch ( RemoteException ex ) {
					ex.printStackTrace();
				}
			}
		}
		clients.clear(); // Plus aucun client n'est lecteur ou ecrivain.
		clients.add(c); // Ajout du nouveau client ecrivain a la liste.
		lock = StateLock.WL; // ServerObject en etat d'ecriture a present.
		maj=false;
		return this.obj;
	}
}
